
.text
.global _start
_start:
@Address Exception Mode in Entry
@0x00000000 Reset                 Supervisor
reset_entry:
    b reset

@0x00000004 Undefined instruction Undefined
    b undef_instruction_entry

@0x00000008 Software Interrupt    Supervisor
    b swi_entry

@0x0000000C Abort (prefetch)      Abort
    b abort_prefetch_entry

@0x00000010 Abort (data)          Abort
    b abort_data_entry

@0x00000014 Reserved              Reserved
reserved_entry:
    b reserved_entry

@0x00000018 IRQ                   IRQ
    b irq_entry @NOTE:when irq occured, svc's next pc instruction was filled to lr automaticly.

@0x0000001C FIQ                   FIQ
    b frq_entry

reset:
    ldr sp, =1024 * 4
    bl close_watch_dog
    bl init_clock
    bl init_sdram
    bl copy_main_code_nand2sdram

	/*
	7  6  5  4  3  2  1  0
	I  F  T  1  0  0  1  0
	|  |  |  -------------
	|  |  |        |_Interupt Mode
	|  |  |_0:not Thumb mode
	|  |_1:disable Fast Interupt
	|_1:disable Interupt
	*/
    msr cpsr_c, #0xd2 @set to irq mode. cpsr_c is cpsr[0:7] bits
    ldr sp, =0x33000000 @0x30000000+16*1024*1024=0x32000000 -> 16M position as irq's stack. [0x33000000, 0x32000000) size:16M

    msr cpsr_c, #0xd3 @switch to svc supervisor mode, and disable interupt
    ldr sp, =1024 * 4


    bl init_irq
    msr cpsr_c, #0x53; @svc mode:open Interupt by setting cpsr_c.I bit

    ldr sp, =0x34000000       @0x30000000+64*1024*1024 64M position   [0x3400000, 0x33000000) size:16M
    ldr lr, =halt_loop        @set return_address
    ldr pc, =pre_main             @jump to pre_main,run on sdram.

halt_loop:
    b halt_loop
    
undef_instruction_entry:
    ldr sp, =0x32f00000       @see taskMgr.c memory arrange
    sub lr, lr, #4
    ldr pc, =on_undef_instruction
    b halt_loop @should not be execute

swi_entry:
    @    ldr sp, =0x32f00000       @see taskMgr.c memory arrange  话说 swi时栈在哪里? 待确认
    stmdb sp!, {r0-r12, lr}
    ldr r0, [lr, #-4]
    bic r0, r0, #0xff000000
	cmp r0, #48 @is reshcedule task request?
	beq on_reshedule_tsk_req

    @general swi
    ldr lr, =ret_swi
    ldr pc,=on_swi_entry
ret_swi:
    ldmia sp!, {r0-r12, pc}^

on_reshedule_tsk_req:
	@step1:save r0-r16 to current task struct register buffer(cur_task_info.regs)
	mov lr, sp @mov rd <op2>  now r0=sp
    ldmia lr, {r0-r12}

	ldr lr, =g_pcurrent_regs @lr = &g_pcurrent_regs
	ldr lr, [lr]             @lr = &g_tsk_mgr.arr[cur_task_idx].r    
    add lr, lr, #52
    stmdb lr, {r0-r12} @lr -> .r13
    
    ldr r0, [sp, #52] @orig pc -> lr
    str r0, [lr, #8]

	mrs r3, spsr @Move PSR status/flags to register   注意这个spsr就是进入中断前的,usr mode的CPSR
	str r3, [lr, #12] @save orig's cpsr -> r.cpsr
    @now the condition is like this
    @               |                |  high addr
    @               | task_entry(fn) |
    @               | pre_task's cpsr|
    @               | pre_task's pc  |
    @               | N/A            | the pre_mod(usr mode)'s lr can not be seen in irq mode
    @               | N/A            | the pre_mod(usr mode)'s sp can not be seen in irq mode
    @               | pre_task's r12 |
    @               | pre_task's r11 |
    @               | pre_task's r10 |
    @               | pre_task's r9  |
    @               | pre_task's r8  |
    @               | pre_task's r7  |
    @               | pre_task's r6  |
    @               | pre_task's r5  |
    @               | pre_task's r4  |
    @               | pre_task's r3  |
    @               | pre_task's r2  |
    @               | pre_task's r1  |
    @ &pre_tsk.r--->| pre_task's r0  |
    @               |                |

	@step2:set =save_sp_and_lr to lr
	ldr r1, =save_sp_and_lr2
	str r1, [sp, #52] @now r0 is point to lr's addr
    @              |                    |
    @              |xx                  |
    @              | fn:save_sp_and_lr2 | <---r0. reset [r0] is safe, because of pre_mode's pc was save to pre_task.r
    @              | pre_task's r12     |
    @              | pre_task's r11     |
    @              | pre_task's r10     |
    @              | pre_task's r9      |
    @              | pre_task's r8      |
    @              | pre_task's r7      |
    @              | pre_task's r6      |
    @              | pre_task's r5      |
    @              | pre_task's r4      |
    @              | pre_task's r3      |
    @              | pre_task's r2      |
    @              | pre_task's r1      |
    @    irq_sp--->| pre_task's r0      |
    @              |         |

	@step3:close interupt  N/A
    @应该禁TIME1的中断  TODO !!!!! 1234

	@step4:run on save_sp_and_lr2
	ldmia sp!, {r0-r12, pc}^ @recover int-mode's sp, and run on schedule
    @执行完ldmia后,立即由irq mode切向user mode,并直接向usr_mode的pc弹save_sp_and_lr2函数地址,执行save_sp_and_lr2函数. 
    @这里虽然也弹了r0-r12主要目的是恢复irq mode的sp值.在切后的usr mode中r0-r12被忽视(未使用前值)

save_sp_and_lr2:
	ldr r0,=g_pcurrent_regs
	ldr r0, [r0]
	add r0, r0, #52 @13*4, now r0 = &pre_task.r.sp_r13
	str sp, [r0]    @由于irq mode 切回 user mode后,一直未使用usr_mode's sp,可知usr_mode's sp从中断发生那刻起,未被改变
	add r0, r0, #4  @now r0 = &pre_task.r.lr_r14
	str lr, [r0]    @由于irq mode 切回 user mode后,一直未使用usr_mode's lr,可知usr_mode's lr从中断发生那刻起,未被改变
    @至此,pre task全部分寄存器状态已被保存到pre_task.r中
    @now the condition is like this
    @               |                |  high addr
    @               | task_entry(fn) |
    @               | pre_task's cpsr|
    @               | pre_task's pc  |
    @               | pre_task's lr  |
    @               | pre_task's sp  |
    @               | pre_task's r12 |
    @               | pre_task's r11 |
    @               | pre_task's r10 |
    @               | pre_task's r9  |
    @               | pre_task's r8  |
    @               | pre_task's r7  |
    @               | pre_task's r6  |
    @               | pre_task's r5  |
    @               | pre_task's r4  |
    @               | pre_task's r3  |
    @               | pre_task's r2  |
    @               | pre_task's r1  |
    @ &pre_tsk.r--->| pre_task's r0  |
    @               |                |

    @执行Task调度, 注意:此时已经是在user mode中,因此调度过程不宜过长,最低限度为下一个Timer1到来时...
	ldr pc, =tsk_schedule2


abort_prefetch_entry:
    ldr sp, =0x32f00000       @see taskMgr.c memory arrange
    sub lr, lr, #4
    stmdb sp!, {r0-r12, lr}
    ldr pc, =on_abort_prefetch
    b halt_loop @should not be execute

@在异常模式下,目前只输出发生异常前的pc及r0~r12的值
@并未对异常发生前的栈信息做任何的提示. 如果想要这样做,这里简单记下步骤及注意事项
@ 1.通过spsr判断异常发生前的mode   如果是同一mode....步骤2-7就不用做,直接输出栈信息.
@ 2.切换到异常发生前的mode, 这里要注意不能切到原现场,以防止同一处异常再发生,以至无限循环. 
@   可切回到一个新立的函数  切前中断是否要关要另行检讨
@ 3.切至新立函数后,取得sp后保存起来(全局变量即可)
@ 4.在新立函数中手动触发同一异常(data abort/undefine instruction/prefetch abort)
@ 5.异常发生后,进来首先要判断这是第一步触发还是第二次(手动)触发  可以保存起来的全局变量是否为0
@ 6.第二次(手动)触发的话,就可以安心的输出栈信息了
@ 7.输出完将全局变量清0
abort_data_entry:
    ldr sp, =0x32f00000       @see taskMgr.c memory arrange
    sub lr, lr, #8
    stmdb sp!, {r0-r12, lr}
    ldr pc, =on_abort_data
    b halt_loop @should not be execute

frq_entry:
    ldr pc, =on_frq
    b halt_loop @should not be execute

irq_entry:
    sub lr, lr, #4 @calc lr, this lr is irq's lr,but the value is filled with the before mode's next instruction when irq occured.
    stmdb sp!, {r0-r12, lr}
    @stmdb      before                  after 
    @           |         |             |                    | high addr
    @ irq_sp--->|xx       |             |xx                  |
    @           |         |             | pre_task's pc(r15) | Exactly,pc-4
    @           |         |             | pre_task's r12     |
    @           |         |             | pre_task's r11     |
    @           |         |             | pre_task's r10     |
    @           |         |             | pre_task's r9      |
    @           |         |             | pre_task's r8      |
    @           |         |             | pre_task's r7      |
    @           |         |             | pre_task's r6      |
    @           |         |             | pre_task's r5      |
    @           |         |             | pre_task's r4      |
    @           |         |             | pre_task's r3      |
    @           |         |             | pre_task's r2      |
    @           |         |             | pre_task's r1      |
    @           |         |   irq_sp--->| pre_task's r0      |
    @           |         |             |                    |

	ldr r0, =0x4A000014 @INTOFFSET addr
	ldr r0, [r0]
	cmp r0, #11 @is INT_TIMER1?
	beq os_timer_irq
	b comm_irq

os_timer_irq:
	@step1:save r0-r16 to current task struct register buffer(cur_task_info.regs)
	mov lr, sp @mov rd <op2>  now r0=sp
    ldmia lr, {r0-r12}

	ldr lr, =g_pcurrent_regs @lr = &g_pcurrent_regs
	ldr lr, [lr]             @lr = &g_tsk_mgr.arr[cur_task_idx].r    
    add lr, lr, #52
    stmdb lr, {r0-r12} @lr -> .r13
    
    ldr r0, [sp, #52] @orig pc -> lr
    str r0, [lr, #8]

	mrs r3, spsr @Move PSR status/flags to register   注意这个spsr就是进入中断前的,usr mode的CPSR
	str r3, [lr, #12] @save orig's cpsr -> r.cpsr
    @now the condition is like this
    @               |                |  high addr
    @               | task_entry(fn) |
    @               | pre_task's cpsr|
    @               | pre_task's pc  |
    @               | N/A            | the pre_mod(usr mode)'s lr can not be seen in irq mode
    @               | N/A            | the pre_mod(usr mode)'s sp can not be seen in irq mode
    @               | pre_task's r12 |
    @               | pre_task's r11 |
    @               | pre_task's r10 |
    @               | pre_task's r9  |
    @               | pre_task's r8  |
    @               | pre_task's r7  |
    @               | pre_task's r6  |
    @               | pre_task's r5  |
    @               | pre_task's r4  |
    @               | pre_task's r3  |
    @               | pre_task's r2  |
    @               | pre_task's r1  |
    @ &pre_tsk.r--->| pre_task's r0  |
    @               |                |

	@step2:set =save_sp_and_lr to lr
	ldr r1, =save_sp_and_lr
	str r1, [sp, #52] @now r0 is point to lr's addr
    @              |                    |
    @              |xx                  |
    @              | fn:save_sp_and_lr  | <---r0. reset [r0] is safe, because of pre_mode's pc was save to pre_task.r
    @              | pre_task's r12     |
    @              | pre_task's r11     |
    @              | pre_task's r10     |
    @              | pre_task's r9      |
    @              | pre_task's r8      |
    @              | pre_task's r7      |
    @              | pre_task's r6      |
    @              | pre_task's r5      |
    @              | pre_task's r4      |
    @              | pre_task's r3      |
    @              | pre_task's r2      |
    @              | pre_task's r1      |
    @    irq_sp--->| pre_task's r0      |
    @              |         |

	@step3:close interupt
	ldr r0, =0x4a000000 @rSRCPND
	@ldr r1, =0x800 @1 << 11
	ldr r1, [r0]
	str r1, [r0]

	ldr r0, =0x4a000010 @rINTPND
	@ldr r1, =0x800 @1 << 11
	ldr r1, [r0]
	str r1, [r0]

	@step4:run on save_sp_and_lr
	ldmia sp!, {r0-r12, pc}^ @recover int-mode's sp, and run on schedule
    @执行完ldmia后,立即由irq mode切向user mode,并直接向usr_mode的pc弹save_sp_and_lr函数地址,执行save_sp_and_lr函数. 
    @这里虽然也弹了r0-r12主要目的是恢复irq mode的sp值.在切后的usr mode中r0-r12被忽视(未使用前值)

save_sp_and_lr:
	ldr r0,=g_pcurrent_regs
	ldr r0, [r0]
	add r0, r0, #52 @13*4, now r0 = &pre_task.r.sp_r13
	str sp, [r0]    @由于irq mode 切回 user mode后,一直未使用usr_mode's sp,可知usr_mode's sp从中断发生那刻起,未被改变
	add r0, r0, #4  @now r0 = &pre_task.r.lr_r14
	str lr, [r0]    @由于irq mode 切回 user mode后,一直未使用usr_mode's lr,可知usr_mode's lr从中断发生那刻起,未被改变
    @至此,pre task全部分寄存器状态已被保存到pre_task.r中
    @now the condition is like this
    @               |                |  high addr
    @               | task_entry(fn) |
    @               | pre_task's cpsr|
    @               | pre_task's pc  |
    @               | pre_task's lr  |
    @               | pre_task's sp  |
    @               | pre_task's r12 |
    @               | pre_task's r11 |
    @               | pre_task's r10 |
    @               | pre_task's r9  |
    @               | pre_task's r8  |
    @               | pre_task's r7  |
    @               | pre_task's r6  |
    @               | pre_task's r5  |
    @               | pre_task's r4  |
    @               | pre_task's r3  |
    @               | pre_task's r2  |
    @               | pre_task's r1  |
    @ &pre_tsk.r--->| pre_task's r0  |
    @               |                |

    @执行Task调度, 注意:此时已经是在user mode中,因此调度过程不宜过长,最低限度为下一个Timer1到来时...
	ldr pc, =tsk_schedule

comm_irq:
    ldr lr, =irq_int_return
    ldr pc, =int_service

irq_int_return:
    @为何要copy SPSR_irq -> CPSR呢?因为进入中断的时候做了这个(手册P78) 
    @1. Copies the CPSR into the SPSR_irq    
    @2.Forces the CPSR mode bits to a IRQ mode
    @这里需要还原原来的状态寄存器,所以必须要拷贝.
    ldmia sp!, {r0-r12, pc}^ @^ means irq's spsr copy to user_mode's cpsr























